package com.ym.core.shiro;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.AbstractValidatingSessionManager;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * Author: zhangfengzhou
 * Date: 2019-03-22
 * Time: 12:00
 * 自定义sessionId获取
 */
public class MySessionManager extends DefaultWebSessionManager {

	private static final String AUTHORIZATION = "Authorization";

	private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";

	public MySessionManager() {
		super();
	}

	@Override
	protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
		String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
		//如果请求头中有 Authorization 则其值为sessionId
		if (!StringUtils.isEmpty(id)) {
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE);
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
			request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);

			//不会把sessionid放在URL后
			request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.FALSE);
			return id;
		} else {
			//否则按默认规则从cookie取sessionId
			return super.getSessionId(request, response);
		}
	}

	@Override
	protected void onChange(Session session) {
		sessionDAO.update(session);
		// 刷新用户ID和token的关系
		ShiroTokenManager.refreshToken(session);
	}

	@Override
	protected void delete(Session session) {
		// 删除用户ID和token的关系，必须先执行这个
		ShiroTokenManager.deleteTokenAfterSessionDelete(session);
		sessionDAO.delete(session);
	}

	/**
	 * 定期检查sesiion过期，浏览器关闭的无效session。或者未成功登录的session
	 *
	 * @param session
	 * @throws InvalidSessionException
	 */
	@Override
	protected void doValidate(Session session) throws InvalidSessionException {
		if (session instanceof ValidatingSession) {
			((ValidatingSession) session).validate();
			Object attribute = session.getAttribute(ShiroTokenManager.DEFAULT_SESSION_KEY_PREFIX_USER);
			if (attribute == null) {
				attribute = session.getAttribute(ShiroTokenManager.DEFAULT_SESSION_KEY_PREFIX_PATIENT);
			}
			if (attribute == null) {
				attribute = session.getAttribute(ShiroTokenManager.DEFAULT_SESSION_KEY_PREFIX_DOCTOR);
			}
			// 登录标志位空，且最后一次使用时间大于30S，判定为过期
			long diffTime = System.currentTimeMillis() - session.getStartTimestamp().getTime();
			if (attribute == null && diffTime > 30000) {
				throw new ExpiredSessionException();
			}
		} else {
			String msg = "The " + getClass().getName() + " implementation only supports validating " +
					"Session implementations of the " + ValidatingSession.class.getName() + " interface.  " +
					"Please either implement this interface in your session implementation or override the " +
					AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";
			throw new IllegalStateException(msg);
		}
	}
}
